/**
 * \file  therapy_gen_imp.cpp
 * \brief implementation of TherapyGenImpl class.
 *
 * ASO: Antiviral Sequence Optimizer
 * <http://aso.googlecode.com/>
 * Copyright (C) 2010 Velez Ezequiel, Peralta Andres, FuDePAN
 *
 * This file is part of the ASO project.
 *
 * Contents:      CPP file for ASO providing class TherapyGenImpl.
 *
 * System:         ASO
 * Language:       C++
 *
 * Author:         Velez Ezequiel, Peralta Andres
 * E-Mail:
 *
 * ASO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ASO is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ASO.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "aso-core/therapy_gen_imp.h"
#define DEBUG

#ifdef DEBUG
size_t cant = 0;
#endif

/*! Implementación de observer de mutantes*/
void TherapyGenImpl::update(const MutantObs* m)
{
    mili::CAutonomousIterator<SequenceSet> mit(m->sequences);
    while (!mit.end())
    {
        ChildId pToChild = pluginInterface->create_node(*mit, m->parent, m->antivirals, m->distance, ++currentId);
#ifdef DEBUG
        ++cant;
#endif
        const TherapyStatus status = pToChild->continue_therapy();
        switch (status)
        {
            case Last :
                {
                    rankerObs->update(new Therapy(pToChild));
                    discard_node(pToChild);
                    break;
                }
            case Continue :
                {
                    rankerObs->update(new Therapy(pToChild));

                    GenerationPolicy::CallbackAction action = generation->node_creation_callback(pToChild, pToChild->scoring());

                    if (action == GenerationPolicy::ProcessChild)
                    {
                        process_node(pToChild);
                    }
                    else if (action == GenerationPolicy::DiscardAndContinueWithSibling)
                    {
                        discard_node(pToChild);
                    }
                    break;
                }
            case Discard :
                {
                    discard_node(pToChild);
                    break;
                }
        }
        ++mit;
    }
    delete m;
}

/*! descarto el nodo *id */
void TherapyGenImpl::discard_node(const ChildId& id)
{
    delete id;
}

/*! procesa el nodo *id */
Score TherapyGenImpl::process_node(const ChildId& id)
{
    AntiviralSelector aVSelect;
    const biopp::PseudoNucSequence sequence = id->sequence;
    AntiviralSet avApply;
    const Score score = id->scoring();
    pluginInterface->get_distance_matrix(matrix);
    aVSelect.select_antivirals(antivirals, sequence, avApply);      // veo los que aplican

    if (!avApply.antivirals.empty())
    {
        CombinationStatus cStatus;
        CombinationObserverImp Obs(sequence, id, this);
        CombinatoryPolicy* combinatoryPolicy = NULL;

        combinatoryPolicy = id->get_combination_policy();

        do
        {
            combinatoryPolicy->combine(avApply.antivirals, &Obs, cStatus); //busco las combinaciones
            if (cStatus.status == Error)
                combinatoryPolicy = id->virologic_failure(cStatus);
        }
        while (cStatus.status == Error && combinatoryPolicy != NULL);

        generation->post_combinations_callback(this);
    }

    discard_node(id);
    return score;
}

void TherapyGenImpl::generateTherapies(const biopp::PseudoNucSequence& initSequence)
{
    TherapyNode* const root = pluginInterface->create_node(initSequence, NULL, AntiviralSet(), ZERO_DISTANCE, currentId);
    process_node(root);
#ifdef DEBUG
    std::cerr << ">>>>> " << cant << " therapies were analyzed" << std::endl;
#endif
}
